package com.pfdu.simplescheduler.node;

import com.pfdu.simplescheduler.config.SimpleSchedulerConfig;
import com.pfdu.simplescheduler.repo.NodeRepo;
import com.pfdu.simplescheduler.strategy.FilterContext;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.DelayQueue;

@Data
@Slf4j
@Component
public class NodeContext {

    /**
     * 应用关闭信号
     */
    private volatile Boolean shutdown = false;

    /**
     * 当前节点的序号
     */
    @Setter(value = AccessLevel.NONE)
    private AppNode currentNode;

    private DelayQueue<HeartBeatDelay> heartBeatQueue = new DelayQueue<>();

    private Thread heartBeatThread = new Thread(() -> this.heartBeat());

    @Autowired
    private SimpleSchedulerConfig config;

    @Autowired
    private NodeRepo nodeRepo;


    //    @PostConstruct
    public void init() {
        // 如果任务筛选策略不是 default，就要与其它节点共享彼此的节点信息。
        // 心跳时机也可以放到 应用启动事件监听器 里面
        if (!FilterContext.DEFAULT.equalsIgnoreCase(config.getStrategy())) {
            heartBeatQueue.offer(new HeartBeatDelay(0));
            heartBeatThread.start();
        }
    }

    public void heartBeat() {
        log.info("AppNode begin heart-beat...");
        while (!shutdown) {
            try {
                HeartBeatDelay heartBeatDelay = heartBeatQueue.take();
                if (heartBeatDelay != null) {
                    handleHeartBeat();
                }
                heartBeatQueue.offer(new HeartBeatDelay(config.getHeartBeatInterval()));
            } catch (InterruptedException e) {
                log.warn("AppNode heart-beat-thread is interrupted when waiting for next heart-beat-time : ");
            }
        }
        log.info("AppNode stop heart-beat.");
    }

    public void destroy() {
        this.shutdown = true;

        if (this.heartBeatThread.isAlive())
            this.heartBeatThread.interrupt();
    }

    public int currentSerialNo() {
        return currentNode.getSerialNo();
    }

    private void handleHeartBeat() {
        // 查看数据库中有没有当前节点，有就更新，没有就注册
        if (currentNode == null || currentNode.getSerialNo() == 0) {
            int maxSerialNo = nodeRepo.maxSerialNo();
            int insertSuccess = nodeRepo.insert(maxSerialNo + 1);
            if (insertSuccess > 0) {
                currentNode = new AppNode();
                currentNode.setSerialNo(maxSerialNo + 1);
            }
        } else
            nodeRepo.updateHeartBeatTime(currentNode.getSerialNo());
    }

}
